/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.ssm.changeunit.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

import net.sf.jazzlib.ZipEntry;
import net.sf.jazzlib.ZipInputStream;
import net.sf.jazzlib.ZipOutputStream;


/**
 *
 * @author user
 */
public class ZipUtil {
       //버퍼 사이즈를 정한다. 한번에 1024byte를 읽어온다.
        private static final byte[] buf = new byte[1024];
                

        /**
         * 디렉토리내의 파일들 혹은 지정한 하나의 파일을 zip파일로 압축한다.
         * @param targetPath
         *                         압축할 디렉토리 또는 파일명
         * @param zipPath
         *                         생성할 zip파일의 경로
         * @throws Exception
         * 
         * ex)ZipUtil.createZipFile("C:\\Test\\", "C:\\Test2\\test.zip") 
         *                 -> Test폴더안의 파일들을 test.zip파일로 압축한다.(Test2디렉토리가 없을경우 에러)
         */
        public static void createZipFile(String targetPath, String zipPath) throws Exception{
                createZipFile(targetPath, zipPath, false);
        }
        
        /**
         * 디렉토리내의 파일들 혹은 지정한 하나의 파일을 zip파일로 압축한다.
         * @param targetPath
         *                         압축할 디렉토리 또는 파일명
         * @param zipPath
         *                         생성할 zip파일의 경로(파일명 포함)
         * @param isDirCre
         *                          zip파일 생성시 생성경로의 디렉토리가 존재하지않을경우 생성여부
         * @throws Exception
         * 
         * ex)ZipUtil.createZipFile("C:\\Test\\", "C:\\Test2\\test.zip", true)
         *                 -> Test폴더안의 파일들을 test.zip파일로 압축한다.(Test2디렉토리가 없을경우 생성)
         */
        public static void createZipFile(String targetPath, String zipPath, boolean isDirCre) throws Exception{
                
                File fTargetPath = new File(targetPath);
                File[] files = null;
                
                //targetPath가 디렉토리일경우...
                if(fTargetPath.isDirectory()){
                        files = fTargetPath.listFiles();
                }
                //targetPath가 파일일경우
                else{
                        files = new File[1];
                        files[0] = fTargetPath;
                }
                
                
                File path = new File(zipPath);
                File dir = null;
                dir = new File(path.getParent());  
                if(isDirCre){
                        //디렉토리가 없을경우 생성
                        dir.mkdirs();
                }
                
                
                //ZIP파일의 output Stream
                ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(path));
                
                //zip파일 압축
                makeZipFile(files, zipOut, "");
                
                //stream을 닫음으로서 zip파일 생성
                zipOut.close();


    }
        
        
        /**
         * zip파일로 압축한다.
         * @param targetFiles
         *                         압축할 파일경로가 있는 String배열
         * @param zipPath
         *                         생성할 zip파일의 경로
         * @throws Exception
         * 
         * ex)String[] src = new String[]{"C:\\AAA.txt", "C:\\BBB.txt", "C:\\CCC.txt"}
         *           ZipUtil.createZipFile(src, "C:\\Test2\\test.zip") 
         *                 -> src배열의 파일들을 test.zip파일로 압축한다.(Test2디렉토리가 없을경우 에러)
         */
        public static void createZipFile(String[] targetFiles, String zipPath) throws Exception{
                createZipFile(targetFiles, zipPath, false);
        }
        
        
        /**
         * zip파일로 압축한다.
         * @param targetFiles
         *                         압축할 파일경로가 있는 String배열
         * @param zipPath
         *                         생성할 zip파일의 경로
         * @param isDirCre
         *                         zip파일 생성시 생성경로의 디렉토리가 존재하지않을경우 생성여부
         * @throws Exception
         * 
         * ex)String[] src = new String[]{"C:\\AAA.txt", "C:\\BBB.txt", "C:\\CCC.txt"}
         *           ZipUtil.createZipFile(src, "C:\\Test2\\test.zip", true) 
         *                 -> src배열의 파일들을 test.zip파일로 압축한다.(Test2디렉토리가 없을경우 생성)
         */
        public static void createZipFile(String[] targetFiles, String zipPath, boolean isDirCre) throws Exception{
                
                File[] files = new File[targetFiles.length];
                for(int i=0; i<files.length; i++){
                        files[i] = new File(targetFiles[i]);
                }
                
                File path = new File(zipPath);
                File dir = null;
                dir = new File(path.getParent());  
                if(isDirCre){
                        //디렉토리가 없을경우 생성
                        dir.mkdirs();
                }
                
                
                //ZIP파일의 output Stream
                ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(path));
                
                //zip파일 압축
                makeZipFile(files, zipOut, "");
                
                //stream을 닫음으로서 zip파일 생성
                zipOut.close();


    }
        
        
        //zip파일로 압축
        private static void makeZipFile(File[] files, ZipOutputStream zipOut, String targetDir) throws Exception{
                
                //디렉토리 내의 파일들을 읽어서 zip Entry로 추가합니다.
                for (int i = 0; i < files.length; i++) {
                        
                        File compPath = new File(files[i].getPath());
                        
                        //목록에서 디렉토리가 존재할경우 재귀호출하여 하위디렉토리까지 압축한다.(머리아픔... 생각많이함.. ㅠ.ㅠ)
                        if(compPath.isDirectory()){
                                File[] subFiles = compPath.listFiles();
                                makeZipFile(subFiles, zipOut, targetDir+compPath.getName()+"/");
                                continue;
                        }
                        
                        FileInputStream in = new FileInputStream(compPath);

                        // ZIP OutputStream에 ZIP entry를 추가 
                        // ZIP파일 내의 압축될 파일이 저장되는 경로이다...(주의!!!)
                        zipOut.putNextEntry(new ZipEntry(targetDir+"/"+files[i].getName()));

                        // 파일을 Zip에 쓴다.
                        int data;

                        while ((data = in.read(buf)) > 0) {
                                zipOut.write(buf, 0, data);
                        }

                        //하나의 파일을 압축하였다.
                        zipOut.closeEntry();
                        in.close();
                        
                }
                
        }
        
        
        /**
         * zip파일의 압축을 해제한다.
         * @param targetZip
         *                         압축을 해제할 zip파일
         * @param completeDir
         *                         압축이 해제된 파일들이 위치할 디렉토리
         * @throws Exception
         * 
         * ex)ZipUtil.unZipFile("c:\\Test\\test.zip", "c:\\Test\\")
         *                 -> test.zip압축파일을 Test디렉토리에 해제한다.
         */
        public static void unZipFile(String targetZip, String completeDir) throws Exception{
                unZipFile(targetZip, completeDir, false);
        }
        
        
        /**
         * zip파일의 압축을 해제한다.
         * @param targetZip
         *                         압축을 해제할 zip파일
         * @param completeDir
         *                         압축이 해제된 파일들이 위치할 디렉토리
         * @param isDirCre
         *                          zip파일 해제시 해제할 위치의 디렉토리가 존재하지않을경우 생성여부
         * @throws Exception
         * 
         * ex)ZipUtil.unZipFile("c:\\Test\\test.zip", "c:\\Test\\", true)
         *                 -> test.zip압축파일을 Test디렉토리에 해제한다.(Test2디렉토리가 없을경우 생성)
         */
        public static void unZipFile(String targetZip, String completeDir, boolean isDirCre) throws Exception{
                
                ZipInputStream in = null;
                
                try{
                
                        File fCompleteDir = null;
                        fCompleteDir = new File(completeDir);
                        if(isDirCre){
                                //디렉토리가 없을경우 생성
                                fCompleteDir.mkdirs();
                        }
                        
                        //zip파일의 input stream을 읽어들인다.
                        in = new ZipInputStream(new FileInputStream(targetZip)); 
                        ZipEntry entry = null;
                        
                        //input stream내의 압축된 파일들을 하나씩 읽어온다.
                        while((entry = in.getNextEntry()) != null){
                                
                                //zip파일의 구조와 동일하게 가기위해 로컬의 디렉토리구조를 만든다.(entry.isDirectory() 안먹음.. 젠장~!)
                                String entryName = entry.getName();
                                if(entry.getName().lastIndexOf('/') > 0){
                                        String mkDirNm = entryName.substring(0, entryName.lastIndexOf('/'));
                                        new File(completeDir+mkDirNm).mkdirs();
                                }
                                
                                //해제할 각각 파일의 output stream을 생성
                                FileOutputStream out = new FileOutputStream(completeDir+entry.getName()); 
                
                    int bytes_read; 
                    while((bytes_read=in.read(buf)) !=-1) 
                            out.write(buf, 0,bytes_read); 
        
                    //하나의 파일이 압축해제되었다.
                    out.close(); 
                        }
                        
                }catch(Exception e){
                        throw new Exception(e);
                }finally{
                        //모든파일의 압축이 해제되면 input stream을 닫는다.
                        in.close(); 
                }
                                
        }
        
        
        
        /**
         * byte배열을 받아서 압축된 byte배열을 리턴한다.
         * @param src
         *                         압축할 byte배열
         * @return        압축된 byte배열
         * @throws Exception
         * 
         * ex)byte[] temp = compressToZip("테스트 데이터입니다.")
         *           String str = new String(temp, "UTF-8")
         *          byte[] ret = compressToZip(src);
         */
        public static byte[] compressToZip(byte[] src) throws Exception{
                
                byte[] retSrc = null;
                ByteArrayOutputStream baos = null;
                
                try{
                        
                        //ZIP파일의 output Stream
                        ByteArrayInputStream bais = new ByteArrayInputStream(src);
                        baos = new ByteArrayOutputStream();
                        ZipOutputStream zos = new ZipOutputStream(baos);
                        
                        zos.putNextEntry(new ZipEntry("temp.tmp"));
                        
                        int bytes_read = 0;
                        //전달받은 src를 압축하여 파일에다 쓴다.
                while((bytes_read=bais.read(buf)) !=-1) {
                        zos.write(buf, 0, bytes_read); 
                }
                bais.close();
                zos.close();
                
                //스트림을 닫은후 byte배열을 얻어온다...(닫기전에 수행하면 정상적으로 얻어오지 못한다.)
                retSrc = baos.toByteArray();
                
                }catch(Exception e){
                        throw new Exception(e);
                }finally{
                        baos.close();
                }
                
                return retSrc;

    }
        
        
        //압축된 byte배열을 받아서 zipPath위치에 zip파일을 생성한다. 
        private static void makeZipFile(byte[] src, String zipPath) throws Exception{
                
                FileOutputStream fos = null;
                ByteArrayInputStream bais = null;

                try{
                        fos = new FileOutputStream(zipPath);
                        bais = new ByteArrayInputStream(src);
        
                        int bytes_read = 0;
                while((bytes_read=bais.read(buf)) !=-1) {
                        fos.write(buf, 0, bytes_read); 
                }
                        
                }catch(Exception e){
                        throw new Exception(e);
                }finally{
                        fos.close();
                        bais.close();
                }
        }
        
        
        /**
         * 압축된 byte배열의 압축을 해제하여 byte배열로 리턴한다.
         * @param src
         *                         압축된 byte배열
         * @return 압축 해제된 byte배열
         * @throws Exception
         * 
         * ex)byte[] src = compressToZip("테스트 데이터입니다.")
         *          unZip(src);         
         */
        public static byte[] unZip(byte[] src) throws Exception{
                
                byte[] retSrc = null;
                ByteArrayOutputStream baos = null;
                ZipInputStream zis = null;
                int bytes_read = 0;
                
                try{
                        zis = new ZipInputStream(new ByteArrayInputStream(src));
                        baos = new ByteArrayOutputStream();
                        
                        zis.getNextEntry();        //entry는 하나밖에 없음을 보장한다.
                        
            while((bytes_read=zis.read(buf)) !=-1) {
                    baos.write(buf, 0,bytes_read); 
            }
            
                        retSrc = baos.toByteArray();
                        
                }catch(Exception e){
                        throw new Exception(e);
                }finally{
                        baos.close();
                        zis.close();
                }
                
                return retSrc;
        }        
        
        
        /**
         * 문자열을 압축하여 byte배열로 리턴한다.(UTF-8)
         * @param src
         *                         압축할 문자열
         * @return 압축된 byte배열(UTF-8)
         * @throws Exception
         * 
         * ex)byte[] temp = compressToZip("테스트 데이터입니다.")
         *           String str = new String(temp, "UTF-8")
         */
        public static byte[] compressToZip(String src) throws Exception {
                return compressToZip(src.getBytes("UTF-8"));
        }
        
        
        
        /**
         * byte배열을 압축하여 zip파일로 생성한다.
         * @param src
         *                         압축할 byte배열
         * @param zipPath
         *                         zip파일이 생성될 경로(파일명 포함.)
         * @throws Exception
         * 
         * ex)String temp = "테스트 데이터입니다.";
         *    byte[] src = temp.getBytes("UTF-8");
         *    srcToZipFile(src, "C:\\test.zip")
         */
        public static void srcToZipFile(byte[] src, String zipPath) throws Exception {
                byte[] retSrc = null;
                
                //압축한다.
                retSrc = compressToZip(src);
                
                //파일로 만든다.
                makeZipFile(retSrc, zipPath);
        }
        
        
        /**
         * byte배열을 압축하여 zip파일로 생성한다.
         * @param src
         *                         압축할 문자열
         * @param zipPath
         *                         zip파일이 생성될 경로(파일명 포함.)
         * @throws Exception
         * 
         * ex)String temp = "테스트 데이터입니다.";
         *    byte[] src = temp.getBytes("UTF-8");
         *    srcToZipFile(src, "C:\\test.zip")
         */
        public static void srcToZipFile(String src, String zipPath) throws Exception {
                byte[] retSrc = null;
                
                //압축한다.
                retSrc = compressToZip(src.getBytes("UTF-8"));
                
                //파일로 만든다.
                makeZipFile(retSrc, zipPath);
        }
        
        
        /**
         * 압축된 zip파일을 해제후 byte배열로 리턴한다.
         * @param zipPath
         *                         압축 해제할 zip파일의 경로(파일명 포함)
         * @throws Exception
         * 
         * ex)String temp = "테스트 데이터입니다.";
         *    byte[] src = temp.getBytes("UTF-8");
         *    srcToZipFile(src, "C:\\test.zip")
         */
        public static byte[] zipFileToSrc(String zipPath) throws Exception {
                byte[] retSrc = null;

                return retSrc;
        }
        
} 

